package com.eic.framework.core.domain;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.eic.framework.core.util.CreateAndUpdateMetaUtils;
import com.eic.framework.core.service.IServicePlus;
import com.eic.framework.core.service.ServiceCacheImpl;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.page.TableDataInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 视图包装基类
 */
public abstract class BaseEntityWrapperV<E, V> {
    protected Logger logger= LoggerFactory.getLogger(getClass());

    /**
     * 单个实体类包装
     *
     * @param entity 实体类
     * @return V
     */
    public abstract V entityVO(E entity);

    /**
     * 实体类集合包装
     *
     * @param list
     * @return List V
     */
    public List<V> listVO(List<E> list) {
        return list.stream().map(this::entityVO).collect(Collectors.toList());
    }

    /**
     * 分页实体类集合包装
     *
     * @param pages 分页
     * @return Page V
     */
    public final TableDataInfo<V> pageVO(IPage<E> pages) {
        TableDataInfo<V> rspData = new TableDataInfo<>();
        rspData.setCode(HttpStatus.SUCCESS);
        rspData.setMsg("查询成功");
        List<V> records = listVO(pages.getRecords());
        rspData.setRows(records);
        rspData.setTotal(pages.getTotal());
        return rspData;
    }
    /**
     * 分页实体类集合包装
     *
     * @param pages 分页
     * @return Page V
     */
    public final TableDataInfo<E> page(IPage<E> pages) {
        TableDataInfo<E> rspData = new TableDataInfo<>();
        rspData.setCode(HttpStatus.SUCCESS);
        rspData.setMsg("查询成功");
        rspData.setRows(pages.getRecords());
        rspData.setTotal(pages.getTotal());
        return rspData;
    }

    protected final String getUserName(String userId){
        return CommonWrapperVFunction.getUserName(userId);
    }

    /**
     * 获取实体类的字段值，如dept.getName同getFieldValue(dept,Dept::getName);
     */
    protected final <T, R> R getFieldValue(T data, Function<T, R> function){
        if(data==null){
            return null;
        }
        return function.apply(data);
    }

    /**
     * 服务按ID查询结果并返回字段值，如deptService.getById(id).getName()同getFieldValue(deptService,id,Dept::getName);
     */
    protected final <T, R> R getFieldValue(IServicePlus<T> service, Serializable id, Function<T, R> function){
        if(!(service instanceof ServiceCacheImpl)){
            logger.warn("服务未启用缓存：{}",service.getClass().getName());
        }
        T data = service.getById(id);
        if(data==null){
            return null;
        }
        return function.apply(data);
    }

    /**
     * 对列表中的每个对象，按外键设置外键值
     * @param voList
     * @param foreignKey 外键字段，如：UserVo::getDeptId
     * @param foreignKeyValue 外键值字段，如：UserVo::setDeptName
     * @param associationService 关联表服务，如：deptService
     * @param associationValue 关联表值字段，如：Dept::getDepartName
     * @param <T> 关联表实体类型
     * @param <K> 外键类型
     * @param <R> 外键值类型
     */
    protected final <T,K extends Serializable,R> void copyForeignKeyData(List<V> voList, Function<V,K> foreignKey, BiConsumer<V,R> foreignKeyValue,
                                                  IServicePlus<T> associationService,Function<T, R> associationValue){
        //外键ID列表
        Set<K> foreignKeySet=new HashSet<>();
        for(V vo:voList){
            K keyId=foreignKey.apply(vo);
            if(keyId!=null){
                foreignKeySet.add(keyId);
            }
        }
        //查询关联表数据,并将结果转为Map（主键-查询字段）
        List<T> assoList=associationService.listByIds(foreignKeySet);
        Map<String,R> assoMap=new HashMap<>();
        for(T assoEntity:assoList){
            try {
                String assoId= CreateAndUpdateMetaUtils.getMeta(assoEntity.getClass()).getPrimaryField().get(assoEntity).toString();
                assoMap.put(assoId,associationValue.apply(assoEntity));
            }catch (Exception e){
                throw new RuntimeException("CreateAndUpdateMetaUtils 查询主键值失败",e);
            }
        }
        //比较外键，设置外键值
        for(V vo:voList){
            K keyId=foreignKey.apply(vo);
            if(keyId!=null){
                R value=assoMap.get(keyId.toString());
                foreignKeyValue.accept(vo,value);
            }
        }
    }
    /**
     * 查询列表中对象外键关联实体对象，并转为Map(key->关联实体)
     * @param voList
     * @param foreignKey 外键字段，如：UserVo::getDeptId
     * @param associationService 关联表服务，如：deptService
     * @param <T> 关联表实体类型
     * @param <K> 外键类型
     */
    protected final <T,K extends Serializable> Map<String,T> mapForeignEntity(List<V> voList, Function<V,K> foreignKey,IServicePlus<T> associationService){
        //外键ID列表
        Set<K> foreignKeySet=new HashSet<>();
        for(V vo:voList){
            K keyId=foreignKey.apply(vo);
            if(keyId!=null){
                foreignKeySet.add(keyId);
            }
        }
        //查询关联表数据,并将结果转为Map（主键-查询字段）
        List<T> assoList=associationService.listByIds(foreignKeySet);
        Map<String,T> assoMap=new HashMap<>();
        for(T assoEntity:assoList){
            try {
                String assoId=CreateAndUpdateMetaUtils.getMeta(assoEntity.getClass()).getPrimaryField().get(assoEntity).toString();
                assoMap.put(assoId,assoEntity);
            }catch (Exception e){
                throw new RuntimeException("CreateAndUpdateMetaUtils 查询主键值失败",e);
            }
        }
        return assoMap;
    }
}

